项目代码

用Java的snakeYaml解析YAML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import org.junit.Test;
import org.yaml.snakeyaml.Yaml;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.alibaba.fastjson.JSON;

public class testload {
@Test
public void load() throws FileNotFoundException{
//初始化Yaml解析器
Yaml yaml = new Yaml();
File f=new File("/Users/wangzulong/mycode/yamtest/src/main/resources/testload.yaml");
//读入文件
Object result= yaml.load(new FileInputStream(f));
System.out.println(result.getClass());
System.out.println( result);
}

@Test
public void loadMap() throws IOException {
Yaml yaml = new Yaml();
Map<String, Object> map = null;
InputStream is = new FileInputStream(new File("/Users/wangzulong/mycode/yamtest/src/main/resources/testload.yaml"));
if (is != null) {
map = (Map<String, Object>) yaml.load(is);
is.close();
}
System.out.println(map);
}

@Test
public void loadObjects() throws IOException {
Yaml yaml = new Yaml();
List<Object> list = null;
InputStream is = new FileInputStream(new File("src/test/resources/example.yaml"));
if (is != null) {
list = new ArrayList<Object>();
for (Object obj : yaml.loadAll(is)) {
list.add(obj);
}
is.close();
}

System.out.println(list);
String json= JSON.toJSONString(list, true);
System.out.println(json);

FileWriter fw = null;
fw = new FileWriter("src/test/resources/topology.json");
BufferedWriter output = new BufferedWriter(fw);
output.write(json);
output.close();
}
}

参考

把json格式数据写入到本地文件

Go Unmarshal处理json数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package main

import (
"encoding/json"
"fmt"
"io/ioutil"
)

func main() {
type Person struct {
Name string
Age int
Gender bool
}

// unmarshal to slice-struct
var ps []Person
fn := "/Users/wangzulong/mycode/go/learn/xxx.json"
bJson, err := ioutil.ReadFile(fn)
// var aJson = `[{"Name":"junbin", "Age":21, "Gender":true},
// {"Name":"junbin", "Age":21, "Gender":true}]`
if err != nil {
fmt.Println("ReadFile: ", err.Error())
return
}
json.Unmarshal([]byte(bJson), &ps)
//result --> [{junbin 21 true} {junbin 21 true}] len is 2
fmt.Println(ps, "len is", len(ps))
fmt.Println(ps[0].Name, ":", ps[0].Age, ":", ps[0].Gender)

}

GO 解析 JSON

Go_Json_Unmarshal_Marshal
JSON与Go

func Marshal

func Marshal(v interface{}) ([]byte, error)

Marshal returns the JSON encoding of v
Marshal 用于将struct对象序列化到JSON对象中

给定Go的数据结构:Message

1
2
3
4
5
type Message struct {
Name string
Body string
Time int64
}

以及Message的一个实例

1
m := Message{"Alice", "Hello", 1294706395881547000}

通过json.Marshal就可以得到一个JSON格式的m:

1
b, err := json.Marshal(m)

如果一切顺利,err将会是nil,b将会是一个包含JSON数据的 []byte

1
b == []byte(`{"Name":"Alice","Body":"Hello","Time":1294706395881547000}`)

只有能够被表示成合法的JSON的数据才会被编码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
package main

import (
"encoding/json"
"fmt"
)

//tag中的第一个参数是用来指定别名
//比如Name 指定别名为 username `json:"username"`
//如果不想指定别名但是想指定其他参数,用逗号来分隔

//omitempty 指定到一个field时
//如果在赋值时没有对该属性赋值,或者对该属性赋值为 zero value
//那么将Person序列化成json时会忽略该字段

//- 指定到一个field时
//无论有没有值将Person序列化成json时都会忽略该字段

//string 指定到一个field时
//比如Person中的Count为int类型 如果没有任何指定在序列化
//到json之后也是int 比如这个样子 "Count":0
//但是如果指定了string之后序列化之后也是string类型的
//那么就是这个样子"Count":"0"

type Person struct {
Name string `json:"username"`
Age int
Gender bool `json:",omitempty"`
Profile string
OmitContent string `json:"-"`
Count int `json:",string"`
}

func main() {
var p *Person = &Person{
Name: "brainwu",
Age: 21,
Gender: true,
Profile: "I am Wujunbin",
OmitContent: "OmitConent",
}
if bs, err := json.Marshal(&p); err != nil {
panic(err)
} else {
//result --> {"username":"brainwu","Age":21,"Gender":true,"Profile":"I am Wujunbin","Count":"0"}
fmt.Println(string(bs))
}

var p2 *Person = &Person{
Name: "brainwu",
Age: 21,
Profile: "I am Wujunbin",
OmitContent: "OmitConent",
}
if bs, err := json.Marshal(&p2); err != nil {
panic(err)
} else {
//result --> {"username":"brainwu","Age":21,"Profile":"I am Wujunbin","Count":"0"}
fmt.Println(string(bs))
}

// slice 序列化为json
var aStr []string = []string{"Go", "Java", "Python", "Android"}
if bs, err := json.Marshal(aStr); err != nil {
panic(err)
} else {
//result --> ["Go","Java","Python","Android"]
fmt.Println(string(bs))
}

//map 序列化为json
var m map[string]string = make(map[string]string)
m["Go"] = "No.1"
m["Java"] = "No.2"
m["C"] = "No.3"
if bs, err := json.Marshal(m); err != nil {
panic(err)
} else {
//result --> {"C":"No.3","Go":"No.1","Java":"No.2"}
fmt.Println(string(bs))
}
}

func Unmarshal

func Unmarshal(data []byte, v interface{}) error

Unmarshal parses the JSON-encoded data and stores the result in the value pointed to by v. If v is nil or not a pointer, Unmarshal returns an InvalidUnmarshalError.
Unmarshal用于反序列化json的函数,根据data将数据反序列化到传入的对象中

首先,声明一个变量用于存放解码后的数据

1
var m Message

然后调用json.Unmarshal,传递参数JSON数据的[]byte以及指向m的指针

1
err := json.Unmarshal(b, &m)

如果b中包含匹配m的合法的JSON,那么函数调用之后,err值为nil,b中的数据会存到结构体m中,就像下面这样的赋值:

1
2
3
4
5
m = Message{
Name: "Alice",
Body: "Hello",
Time: 1294706395881547000,
}

对于一个给定的 JSON key “Foo”,Unmarshal会查询结构体的域来寻找(in order of preference):

  1. 一个带有标签”Foo” 的可导出域(更多关于结构体标签见Go spec)

  2. 一个名为”Foo” 的可导出域

  3. 或者一个名为”FOO” 或者 “FoO 或者其他大小写的匹配”Foo”的可导出域

当 JSON 数据结构跟 Go 类型不一致时:

1
2
3
b := []byte(`{"Name":"Bob","Food":"Pickle"}`)
var m Message
err := json.Unmarshal(b, &m)

Unmarshal只会解码在目标类型中出现的域。
在上面的例子中,m只有Name域会被填充,Food域将被忽略。这种行为在你想从一个大的JSON blob中选择几个指定的域时会特别有用。这也意味着Unmarshal不会影响目标结构体中的不可导出域。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package main

import (
"encoding/json"
"fmt"
)

func main() {
type Person struct {
Name string
Age int
Gender bool
}
//unmarshal to struct
var p Person
var str = `{"Name":"junbin", "Age":21, "Gender":true}`
json.Unmarshal([]byte(str), &p)
//result --> junbin : 21 : true
fmt.Println(p.Name, ":", p.Age, ":", p.Gender)

// unmarshal to slice-struct
var ps []Person
var aJson = `[{"Name":"junbin", "Age":21, "Gender":true},
{"Name":"junbin", "Age":21, "Gender":true}]`
json.Unmarshal([]byte(aJson), &ps)
//result --> [{junbin 21 true} {junbin 21 true}] len is 2
fmt.Println(ps, "len is", len(ps))

// unmarshal to map[string]interface{}
var obj interface{} // var obj map[string]interface{}
json.Unmarshal([]byte(str), &obj)
m := obj.(map[string]interface{})
//result --> junbin : 21 : true
fmt.Println(m["Name"], ":", m["Age"], ":", m["Gender"])

//unmarshal to slice
var strs string = `["Go", "Java", "C", "Php"]`
var aStr []string
json.Unmarshal([]byte(strs), &aStr)
//result --> [Go Java C Php] len is 4
fmt.Println(aStr, " len is", len(aStr))
}

Unmarshal json into struct: cannot unmarshal array into Go value
用结构体也可以解决

interface{} 空接口

interface{}类型(空接口)表示一个没有方法的接口。每一个Go类型至少实现了0个方法,因此都符合空接口。

空接口可以作为一个通用的容器类型:

1
2
3
4
var i interface{}
i = "a string"
i = 2011
i = 2.777

类型断言可以访问底层的具体类型:

1
2
r := i.(float64)
fmt.Println("the circle's area", math.Pi*r*r)

或者,如果底层的类型是未知的,通过类型switch来确定类型:

1
2
3
4
5
6
7
8
9
10
11
switch v := i.(type) {
case int:
fmt.Println("twice i is", v*2)
case float64:
fmt.Println("the reciprocal of i is", 1/v)
case string:
h := len(v) / 2
fmt.Println("i swapped by halves is", v[h:]+v[:h])
default:
// i isn't one of the types above
}

json 包使用 map[string]interface{} 和 []interface{} 来存储任意 JSON objects 以及 arrays;它很乐意将任意合法的 JSON blob unmarshal 到普通的 interface{} 中。默认的具体 Go 类型是:

1
2
3
4
bool JSON booleans
float64 JSON numbers
string JSON strings
nil JSON null

解码任意数据

考虑这样一个存放在变量b中的JSON数据:

1
b := []byte(`{"Name":"Wednesday","Age":6,"Parents":["Gomez","Morticia"]}`)

当不知道数据结构时,我们可以将它Unmarshal到interface{} :

1
2
var f interface{}
err := json.Unmarshal(b, &f)

现在f中的值就是一个map,key为字符串,值就是以空接口存储的自身:

1
2
3
4
5
6
7
8
f = map[string]interface{}{
"Name": "Wednesday",
"Age": 6,
"Parents": []interface{}{
"Gomez",
"Morticia",
},
}

要访问这样的数据,我们通过类型断言来访问f底层的map[string]interface{}:

1
m := f.(map[string]interface{})

通过 range 语句来迭代map,并通过类型选择来访问具体类型的值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
for k, v := range m {
switch vv := v.(type) {
case string:
fmt.Println(k, "is string", vv)
case int:
fmt.Println(k, "is int", vv)
case []interface{}:
fmt.Println(k, "is an array:")
for i, u := range vv {
fmt.Println(i, u)
}
default:
fmt.Println(k, "is of a type I don't know how to handle")
}
}

通过这种方式我们可以访问未知的 JSON 数据,同时还获得了类型安全的好处。

解析RawMessage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package main

import (
"encoding/json"
"fmt"
"log"
)

func main() {
type Color struct {
Space string
Point json.RawMessage // delay parsing until we know the color space
}
type RGB struct {
R uint8
G uint8
B uint8
}
type YCbCr struct {
Y uint8
Cb int8
Cr int8
}

var j = []byte(`[
{"Space": "YCbCr", "Point": {"Y": 255, "Cb": 0, "Cr": -10}},
{"Space": "RGB", "Point": {"R": 98, "G": 218, "B": 255}}
]`)
var colors []Color
err := json.Unmarshal(j, &colors)
if err != nil {
log.Fatalln("error:", err)
}

for _, c := range colors {
var dst interface{}
switch c.Space {
case "RGB":
dst = new(RGB)
case "YCbCr":
dst = new(YCbCr)
}
err := json.Unmarshal(c.Point, dst)
if err != nil {
log.Fatalln("error:", err)
}
fmt.Println(c.Space, dst)
}
}

流式编解码

json 包提供了DecoderEncoder 用来支持JSON 数据流的读写。函数NewDecoderNewEncoder 封装了io.Readerio.Writer 接口类型。

func NewDecoder(r io.Reader) *Decoder
func NewEncoder(w io.Writer) *Encoder

下面是一个从标准输入读入连续的JSON object的实例程序,每个结构体只留下Name域,然后把objects写到标准输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main

import (
"encoding/json"
"log"
"os"
)

func main() {
dec := json.NewDecoder(os.Stdin)
enc := json.NewEncoder(os.Stdout)
for {
var v map[string]interface{}
if err := dec.Decode(&v); err != nil {
log.Println(err)
return
}
for k := range v {
if k != "Name" {
delete(v, k)
}
}
if err := enc.Encode(&v); err != nil {
log.Println(err)
}
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package main

import (
"fmt"
"encoding/json"
)

type desc struct {
Lang string `json:"lang"`
Content string `json:"content"`
}
type DescSlice struct {
Desc []desc `json:"body"`
}

func main() {
app1 := `{"lang":"ch", "content":"1233456"}`
var info1 desc
err := json.Unmarshal([]byte(app1), &info1)
if err != nil {
fmt.Printf("error is %v\n", err)
} else {
fmt.Printf("%v\n", info1)
}


app2 := `[{"lang":"ch01","content":"1233456"},{"lang":"ch02","content":"1233456"}]`
var info2 []desc
err = json.Unmarshal([]byte(app2), &info2)
if err != nil {
fmt.Printf("error is %v\n", err)
} else {
fmt.Printf("%v\n", info2)
}

app3 := `{"body":[{"lang":"ch01","content":"1233456"},{"lang":"ch02","content":"1233456"}]}`
info3 := DescSlice{}
err = json.Unmarshal([]byte(app3), &info3)
if err != nil {
fmt.Println("error is %v\n", err)
} else {
fmt.Printf("%v\n", info3)
}
}

io/ioutil 包中的函数和方法

ReadAll 读取 r 中的所有数据

func ReadAll(r io.Reader) ([]byte, error)

返回读取的数据和读取过程中遇到的任何错误
如果读取成功,则 err 返回 nil,而不是 EOF

1
2
3
4
5
6
func main() {
s := strings.NewReader("Hello World!")
ra, _ := ioutil.ReadAll(s)
fmt.Printf("%s", ra)
// Hello World!
}

ReadFile 读取文件中的所有数据

func ReadFile(filename string) ([]byte, error)

返回读取的数据和读取过程中遇到的任何错误
如果读取成功,则 err 返回 nil,而不是 EOF

1
2
3
4
func main() {
ra, _ := ioutil.ReadFile("filepath")
fmt.Printf("%s", ra)
}

WriteFile 向文件 filename 中写入数据 data

func WriteFile(filename string, data []byte, perm os.FileMode) error

如果文件不存在,则以 perm 权限创建该文件
如果文件存在,则先清空文件,然后再写入
返回写入过程中遇到的任何错误

1
2
3
4
5
6
7
8
func main() {
fn := "C:\\Test.txt"
s := []byte("Hello World!")
ioutil.WriteFile(fn, s, os.ModeAppend)
rf, _ := ioutil.ReadFile(fn)
fmt.Printf("%s", rf)
// Hello World!
}

ReadDir 读取目录 dirmane 中的所有目录和文件(不包括子目录)

func ReadDir(dirname string) ([]os.FileInfo, error)

返回读取到的文件的信息列表和读取过程中遇到的任何错误
返回的文件列表是经过排序的

1
2
3
4
5
6
7
8
9
10
11
12
13
func main() {
rd, err := ioutil.ReadDir("C:\\Windows")
for _, fi := range rd {
fmt.Println("")
fmt.Println(fi.Name())
fmt.Println(fi.IsDir())
fmt.Println(fi.Size())
fmt.Println(fi.ModTime())
fmt.Println(fi.Mode())
}
fmt.Println("")
fmt.Println(err)
}

Discard 是一个 io.Writer,对它进行的任何 Write 调用都将无条件成功。
devNull优化的实现了ReadFrom,因此io.Copy到ioutil.Discard避免了不必要的工作,但是ioutil.Discard不记录copy得到的数值

var Discard io.Writer = devNull(0)

ReadCloser 接口组合了基本的 Read 和 Close 方法。NopCloser 将提供的 Reader r 用空操作 Close 方法包装后作为 ReadCloser 返回。

1
2
3
4
5
6
7
8
func main() {
s := strings.NewReader("hello world!")
r := ioutil.NopCloser(s)
r.Close()
p := make([]byte, 10)
r.Read(p)
fmt.Println(string(p)) //hello worl
}

TempFile 在目录 dir 中创建一个临时文件并将其打开

func TempFile(dir, prefix string) (f *os.File, err error)

返回创建的文件的对象和创建过程中遇到的任何错误
如果 dir 为空,则在系统的临时目录中创建临时文件
如果环境变量中没有设置系统临时目录,则在 /tmp 中创建临时文件
调用者可以通过 f.Name() 方法获取临时文件的完整路径
调用 TempFile 所创建的临时文件,应该由调用者自己移除

1
2
3
4
5
func main() {
dn := "C:\\"
f, _ := ioutil.TempFile(dn, "Test")
fmt.Printf("%s", f.Name())
}

TempDir 功能同 TempFile,只不过创建的是目录, 返回值也只返目录的完整路径

func TempDir(dir, prefix string) (name string, err error)
1
2
3
4
5
func main() {
dn := "C:\\"
f, _ := ioutil.TempDir(dn, "Test")
fmt.Printf("%s", f.Name())
}

json iterator

https://github.com/json-iterator/go

http://jsoniter.com/migrate-from-go-std.html